package com.gitee.hermer.engine.jars.core.zipkin.filter;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.EngineMappingRegistrationCache;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;

import com.gitee.hermer.boot.jee.commons.bean.utils.BeanLocator;
import com.gitee.hermer.boot.jee.commons.log.UtilsContext;
import com.gitee.hermer.engine.jars.app.sdk.EngineAppClassLoader;
import com.gitee.hermer.engine.jars.core.context.IEngineAppContext;
import com.gitee.hermer.engine.jars.core.context.domain.EngineAppInfoContext;

import brave.http.HttpTracing;
import brave.servlet.TracingFilter;

public final class EngineZipkinTracingFilter extends UtilsContext implements Filter{

	protected final static ConcurrentHashMap<ClassLoader,Filter> delegates = new ConcurrentHashMap<>(); // servlet ensures create is directly followed by init, so no need for volatile

	public static void release(){
		delegates.remove(Thread.currentThread().getContextClassLoader());
	}
	
	
	@Override
	public void destroy() {

	}

	@Autowired(required=true)
	private IEngineAppContext appContext;

	@Override
	public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
			throws IOException, ServletException {
		Filter tracingFilter = null;
		try{
			HttpServletRequest http = (HttpServletRequest) arg0;
			List<RequestMappingInfo> mappingInfos = EngineMappingRegistrationCache.getInstance().getUrlLookup().get(http.getServletPath());
			if(mappingInfos != null){
				for (RequestMappingInfo requestMappingInfo : mappingInfos) {
					if(requestMappingInfo.getMatchingCondition(http) != null){
						HandlerMethod method = EngineMappingRegistrationCache.getInstance().getMappingLookup().get(requestMappingInfo);
						if(method.getClassLoader() instanceof EngineAppClassLoader){
							EngineAppClassLoader classLoader = (EngineAppClassLoader)method.getClassLoader();
							if(delegates.containsKey(classLoader)){
								tracingFilter = delegates.get(classLoader);
							}else{
								EngineAppInfoContext context = appContext.getEnableAppModelContext(classLoader.getCacheKey());
								HttpTracing httpTracing = context.getJobContext().getContext().getBean(HttpTracing.class);
								tracingFilter = TracingFilter.create(httpTracing);
								delegates.put(classLoader, tracingFilter);
							}
							break;
						}
					}
				}
			}
		}catch (Exception e) {
			error(e.getMessage(),e);
		}
		if(tracingFilter != null){
			tracingFilter.doFilter(arg0, arg1, arg2);
		}else{
			arg2.doFilter(arg0, arg1);
		}
	}

	@Override
	public void init(FilterConfig arg0) throws ServletException {
		try{
			if(appContext == null)
				appContext = BeanLocator.getBean(IEngineAppContext.class);
		}catch (Exception e) {
			throw new ServletException(e.getMessage(),e);
		}
	}

}
